/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
// Copyright tang.  All rights reserved.
// https://gitee.com/inrgihc/dbswitch
//
// Use of this source code is governed by a BSD-style license
//
// Author: tang (inrgihc@126.com)
// Data : 2020/1/2
// Location: beijing , china
/////////////////////////////////////////////////////////////
package com.je.meta.service.dbswitch.service.impl.metadata;

import com.je.ibatis.extension.plugins.pagination.Page;
import com.je.meta.model.database.*;
import com.je.meta.model.database.type.ProductTypeEnum;
import com.je.meta.service.dbswitch.service.AbstractDatabase;
import com.je.meta.service.dbswitch.service.DatabaseFactory;
import com.je.meta.service.dbswitch.service.IMetaDataByJdbcService;
import com.je.meta.util.database.ConnectionUtils;
import com.je.meta.util.database.GenerateSqlUtils;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 使用JDBC连接串的元数据获取服务
 *
 * @author tang
 */
public class MetaDataByJdbcServiceImpl implements IMetaDataByJdbcService {

    protected ProductTypeEnum dbType;
    protected AbstractDatabase database;

    public MetaDataByJdbcServiceImpl(ProductTypeEnum type) {
        this.dbType = type;
        this.database = DatabaseFactory.getDatabaseInstance(type);
    }

    @Override
    public ProductTypeEnum getDatabaseType() {
        return this.dbType;
    }

    @Override
    public List<String> querySchemaList(String jdbcUrl, String username, String password) {
        try (Connection connection = ConnectionUtils.connect(jdbcUrl, username, password)) {
            return database.querySchemaList(connection);
        } catch (SQLException se) {
            throw new RuntimeException(se);
        }
    }

    @Override
    public Page queryTableList(String jdbcUrl, String username, String password,
                               String schemaName) {
        return queryTableList(jdbcUrl, username, password, schemaName, "", "");
    }

    @Override
    public Page queryTableList(String jdbcUrl, String username, String password,
                               String schemaName, String productId, String fuzzyValue) {
        return queryTableList(jdbcUrl, username, password, schemaName, productId, fuzzyValue, 1, 30);
    }

    @Override
    public Page queryTableList(String jdbcUrl, String username, String password, String schemaName,
                               String productId, String fuzzyValue, int intPage, int intLimit) {
        try (Connection connection = ConnectionUtils.connect(jdbcUrl, username, password)) {
            return database.queryTableList(connection, schemaName, productId, fuzzyValue, intPage, intLimit);
        } catch (SQLException se) {
            throw new RuntimeException(se);
        }
    }


    @Override
    public String getTableDDL(String jdbcUrl, String username, String password, String schemaName,
                              String tableName) {
        try (Connection connection = ConnectionUtils.connect(jdbcUrl, username, password)) {
            return database.getTableDDL(connection, schemaName, tableName);
        } catch (SQLException se) {
            throw new RuntimeException(se);
        }
    }

    @Override
    public String getViewDDL(String jdbcUrl, String username, String password, String schemaName,
                             String tableName) {
        try (Connection connection = ConnectionUtils.connect(jdbcUrl, username, password)) {
            return database.getViewDDL(connection, schemaName, tableName);
        } catch (SQLException se) {
            throw new RuntimeException(se);
        }
    }

    @Override
    public List<ColumnDescription> queryTableColumnMeta(String jdbcUrl, String username,
                                                        String password, String schemaName, String tableName) {
        try (Connection connection = ConnectionUtils.connect(jdbcUrl, username, password)) {
            return database.queryTableColumnMeta(connection, schemaName, tableName);
        } catch (SQLException se) {
            throw new RuntimeException(se);
        }
    }

    @Override
    public List<ColumnDescription> querySqlColumnMeta(String jdbcUrl, String username,
                                                      String password, String querySql) {
        try (Connection connection = ConnectionUtils.connect(jdbcUrl, username, password)) {
            return database.querySelectSqlColumnMeta(connection, querySql);
        } catch (SQLException se) {
            throw new RuntimeException(se);
        }
    }

    @Override
    public List<String> queryTablePrimaryKeys(String jdbcUrl, String username, String password,
                                              String schemaName, String tableName) {
        try (Connection connection = ConnectionUtils.connect(jdbcUrl, username, password)) {
            return database.queryTablePrimaryKeys(connection, schemaName, tableName);
        } catch (SQLException se) {
            throw new RuntimeException(se);
        }
    }

    @Override
    public SchemaTableMeta queryTableMeta(String jdbcUrl, String username, String password,
                                          String schemaName, String tableName) {
        try (Connection connection = ConnectionUtils.connect(jdbcUrl, username, password)) {
            return buildSchemaTableMeta(connection, schemaName, tableName);
        } catch (SQLException se) {
            throw new RuntimeException(se);
        }
    }

    @Override
    public List<SchemaTableMeta> queryTablesMeta(String jdbcUrl, String username, String password,
                                                 String schemaName, String tableNames) {
        List<SchemaTableMeta> list = new ArrayList<>();
        try (Connection connection = ConnectionUtils.connect(jdbcUrl, username, password)) {
            for (String tableName : tableNames.split(",")) {
                list.add(buildSchemaTableMeta(connection, schemaName, tableName));
            }
            return list;
        } catch (SQLException se) {
            throw new RuntimeException(se);
        }
    }

    @Override
    public void updateTableColumnMeta(List<SchemaTableMeta> list, String syParent, String productId) {
        database.updateJeTableMetaBySchemaTableMeta(list, syParent, productId);
    }

    private SchemaTableMeta buildSchemaTableMeta(Connection connection, String schemaName, String tableName) {
        SchemaTableMeta tableMeta = new SchemaTableMeta();
        tableMeta.setSchemaName(schemaName);
        tableMeta.setTableCode(tableName);
        //备注
        TableDescription tableDesc = database.queryTableMeta(connection, schemaName, tableName);
        if (null == tableDesc) {
            throw new IllegalArgumentException("Table Or View Not Exist");
        }
        tableMeta.setTableType(tableDesc.getTableType());
        tableMeta.setTableName(tableDesc.getTableName());
        //列
        List<ColumnDescription> columns = database.queryTableColumnMeta(connection, schemaName, tableName);
        //主键
        List<String> pks;
        //外键
        List<ImportedKeyData> importedKeyDataList = database.getTableImportedKeyData(connection, schemaName, tableName, tableMeta);
        //索引
        List<IndexesData> indexesList = database.getTableIndexesDataData(connection, schemaName, tableName, columns);
        //ddl Sql
        String createSql;
        if (tableDesc.isViewTable()) {
            pks = Collections.emptyList();
            createSql = database.getViewDDL(connection, schemaName, tableName);
        } else {
            pks = database.queryTablePrimaryKeys(connection, schemaName, tableName);
            createSql = database.getTableDDL(connection, schemaName, tableName);
        }
        tableMeta.setColumns(columns);
        tableMeta.setPrimaryKeys(pks);
        tableMeta.setIndexesData(indexesList);
        tableMeta.setImportedKeyData(importedKeyDataList);
        tableMeta.setCreateSql(createSql);
        database.buildTableKeyGenerator(tableMeta, pks, columns);
        return tableMeta;
    }

    @Override
    public SchemaTableData queryTableData(String jdbcUrl, String username, String password,
                                          String schemaName, String tableName, int rowCount) {
        try (Connection connection = ConnectionUtils.connect(jdbcUrl, username, password)) {
            return database.queryTableData(connection, schemaName, tableName, rowCount);
        } catch (SQLException se) {
            throw new RuntimeException(se);
        }
    }

    @Override
    public void testQuerySQL(String jdbcUrl, String username, String password, String sql) {
        try (Connection connection = ConnectionUtils.connect(jdbcUrl, username, password)) {
            database.testQuerySQL(connection, sql);
        } catch (SQLException se) {
            throw new RuntimeException(se);
        }
    }

    @Override
    public String getDDLCreateTableSQL(ProductTypeEnum type, List<ColumnDescription> fieldNames,
                                       List<String> primaryKeys, String schemaName, String tableName, boolean autoIncr) {
        return GenerateSqlUtils.getDDLCreateTableSQL(
                type, fieldNames, primaryKeys, schemaName, tableName, autoIncr);
    }

}
